from django.shortcuts import render, redirect
from django.http import Http404, HttpResponse, HttpResponseRedirect, FileResponse, StreamingHttpResponse
from django.template import loader
from django.urls import reverse
from django.core import mail
from generate_yaml.forms import Syaml, Tyaml
from django.contrib import messages
from Automated_Testing import settings
from Method_Decorate import Decoration, zip_file, Inside_action
from file_manage import models
import subprocess
from django.contrib.sessions.models import Session
from requests import session
# 跨站伪造csrf
from django.views.decorators.csrf import csrf_exempt
import json
import time
import sys
import os
import random
import string

"""自动化测试的代码"""
sys.path.append("..")
from Auto_Code import genSCase
from Auto_Code import genTotalCase
from Auto_Code import main

# 文件路径！！TODO:登录状态的判定，以及导航用户名的显示
# app的位置
# app_num_path={0:None,"JULONG":"Src_Code\\APP_work\\ccm_auto_test\\app_x86"}
"""大文件夹"""
file_folder = "/Tmp_File"
"""小文件夹"""
S_folder = "/Gen_S_Yaml"
T_folder = "/Collection_S_Yaml"
T_folder_gen = "/Gen_T_Yaml"
report_folder = "/Report_File"
zip_folder = "/zipfile"


# # Create your views here.
# #总索引
class All_index():
    pass


# 小yaml生成  默认值 name=versirity
# class Small_gen():
#     pass
# 大yaml生成
Total_attri = ['description', 'bundle']
small_attri = ['author', 'name', 'search_pattern', 'match_pattern', 'file_path', 'start', 'end', 'purpose']


@Decoration.check_login
@csrf_exempt  # CSRF必用
def Total_gen(request):
    """
    中间站，获得表单信息，总用例生成
    :param request:
    :return:
    """
    # 获取表单数据
    if request.method == 'POST':  # 如果为post则必须要提交
        T_form = Tyaml()
        if request.session['count_id'] == "0":  # 证明上传过文件
            messages.error(request, "请上传文件后进行提交")
            # 重定向回原页面
            return redirect(reverse('generate_yaml:total_gener'))
            # return HttpResponse(t.render(context, request))
        else:
            tmp = {}
            tmp['name'] = request.session.session_key
            tmp['descrption'] = ''
            tmp['status'] = 'pass'
            tmp['path_load'] = request.session['upload_folder']
            # TODO 获取上一级目录名！通过它来搜索
            tmp['case_path'] = os.path.abspath(
                os.path.join(os.getcwd(), "..")) + file_folder + T_folder_gen  # r"Src_Code\Tmp-django\Tmp_File"
            file_name, path_case = genTotalCase.Gen_Total_Yaml(tmp)  # 生成总用例
            context = {'file_name': file_name}
            t = loader.get_template('process/download_h.html')
            download_url = reverse("generate_yaml:download_page", kwargs={'file_name': str(file_name)})
            context_fun = {}
            context_fun['t_yaml_file_path'] = path_case
            request.session['msg'] = context_fun
            request.session['download_id'] = 1

            Inside_action.up_load_to_file_manage(request.session['user_id'], path_case, "Total")

            return redirect(download_url)


# 小用例上传用于总用例

@csrf_exempt  # CSRF空置 todo:后续加上
def Upload_Sy(request):
    """
    小用例上传，用于生成总用例
    :param request:
    :return:
    """
    if request.method == 'POST':
        file = request.FILES.get('file')  # 获取文件对象，包括文件名文件大小和文件内容
        curttime = time.strftime("%Y%m%d")
        folder = time.strftime("%H_%M_%S")
        # if request.session['count_id']=="0" and request.session['count_id']:
        #     folder = ''.join(random.sample(string.ascii_letters + string.digits, 20))
        request.session['count_id'] += "1"
        request.session['curttime'] = curttime
        # 规定上传目录
        request.session['upload_folder'] = os.path.join(settings.MEDIA_ROOT, 'Collection_S_Yaml', curttime,
                                                        request.session["user_id"], folder)
        upload_url = request.session['upload_folder']
        # 判断文件夹是否存在
        folder = os.path.exists(upload_url)
        if not folder:
            os.makedirs(upload_url)
            print("创建文件夹")
        if file:
            file_name = file.name
            # 判断文件是是否重名，重名了，文件名加时间
            if os.path.exists(os.path.join(upload_url, file_name)):
                name, etx = os.path.splitext(file_name)
                addtime = time.strftime("%Y%m%d%H%M%S")
                finally_name = name + "_" + addtime + etx
                # print(name, etx, finally_name)
            else:
                finally_name = file.name
            # 文件分块上传
            upload_file_to = open(os.path.join(upload_url, finally_name), 'wb+')
            for chunk in file.chunks():
                upload_file_to.write(chunk)
            upload_file_to.close()
            # 返回文件的URl
            file_upload_url = settings.MEDIA_URL + 'attachment/' + curttime + '/' + finally_name
            # 构建返回值
            response_data = {}
            response_data['FileName'] = file_name
            response_data['FileUrl'] = file_upload_url
            response_json_data = json.dumps(response_data)  # 转化为Json格式

            return HttpResponse(response_json_data)
    else:
        # T_form=Tyaml()
        # 标识位  下次访问重新生成ranstr  #刷新后重新记录
        pass
        request.session['count_id'] = "0"
        # 生成随机字符 用于身份判别
        # request.session['ran_id'] = ''.join(random.sample(string.ascii_letters + string.digits, 20))
    t = loader.get_template('generate/Gener_TY.html')
    context = {'username': request.session['user_id']}
    return HttpResponse(t.render(context, request))


# upload method


# 小用例生成
@Decoration.check_login
def Small_gen(request):
    """
    小用例生成
    :param request:
    :return:
    """
    if request.method == 'POST':
        S_form = Syaml(request.POST)
        S_form.is_valid()
        if S_form.cleaned_data['search_s'] == 'never':
            messages.error(request, "没有选择搜索模式")
        elif S_form.cleaned_data['start_s'] == '0' or S_form.cleaned_data['end_s'] == '0':
            messages.error(request, "没有选择开始或者结束的命令")
        # if S_form.is_valid() and S_form.cleaned_data['search_s']!='never':
        else:
            temp_s = {}
            for key1 in Total_attri:
                temp_s[key1] = {}
                for key2 in small_attri:
                    temp_s[key1][key2] = ''
            temp_s['description']['author'] = S_form.cleaned_data['author_s']
            temp_s['description']['name'] = S_form.cleaned_data['name_s']
            temp_s['description']['search_pattern'] = S_form.cleaned_data['search_s']
            temp_s['description']['match_pattern'] = S_form.cleaned_data['match_s']
            temp_s['bundle']['file_path'] = S_form.cleaned_data['file_path']
            temp_s['bundle']['start'] = S_form.cleaned_data['start_s']
            temp_s['bundle']['end'] = S_form.cleaned_data['end_s']
            temp_s['description']['purpose'] = S_form.cleaned_data['purpos_s']
            # TODO 未来解耦  获取上一级目录名！通过它来搜索
            store_path = os.path.abspath(os.path.join(os.getcwd(), "..")) + file_folder + S_folder
            gen_yaml_path = genSCase.Generate_Small(temp_s, store_path)  # str
            filename = os.path.basename(gen_yaml_path)
            # return HttpResponseRedirect('SY/Download')
            login_url = reverse("generate_yaml:download_page", kwargs={'file_name': str(filename)})  # 错误点：不能带有/字符
            context_fun = {}
            context_fun['s_yaml_file_path'] = gen_yaml_path
            request.session['msg'] = context_fun
            # 跳转返回
            request.session['download_id'] = 0
            return redirect(login_url)  # 传入filename
    else:
        # 如果是以get请求消息则显示空表单
        S_form = Syaml()
    t = loader.get_template('generate/Gener_SY.html')
    context = {'S_form': S_form, 'username': request.session['user_id']}
    return HttpResponse(t.render(context, request))


@Decoration.check_login
def download_file(request):
    """
    负责小用例，总用例和测试报告的下载方法
    :param request:
    download_id：0：小 1：总  2:测试报告
    :return:
    """
    # tmp_session=request.session.get('msg')
    if request.session['download_id'] == 0:
        file_path = request.session['msg']['s_yaml_file_path']
    elif request.session['download_id'] == 1:
        file_path = request.session['msg']['t_yaml_file_path']
    elif request.session['download_id'] == 2:
        file_path = request.session['msg']['Auto_process_path']
    ext = os.path.basename(file_path).split('.')[-1].lower()  # 分离文件后缀

    # httpresopnse 允许传入迭代器 采用迭代器访问 防止服务器内存压力过大
    def file_iterator(file_path, chunk_size=512):
        """必须为rb 二进制流"""
        with open(file_path, 'rb') as f:
            while True:
                c = f.read(chunk_size)
                if c:
                    yield c
                else:
                    break

    try:
        if ext == 'yaml' or ext == 'zip':
            # 按文件流下载
            file_name = os.path.basename(file_path)
            response = StreamingHttpResponse(file_iterator(file_path))
            response['Content-Type'] = 'application/octet-stream'
            response['Content-Disposition'] = 'attachment;filename={0}'.format(file_name)
            return response
        else:
            messages.success(request, "非yaml文件禁止下载")
            raise ("download format is failed!")
    except Exception as e:
        print("download error(%s)" % file_path)  # http404


# 用例下载

def PAGE_download(request, file_name=None):
    """
    用例下载界面，兼发送邮件
    :param request:
    :param file_name:文件名
    :return:
    """
    # if request.session['download_id'] == 0:
    #     file_path = request.session['msg']['s_yaml_file_path']
    # elif request.session['download_id'] == 1:
    #     file_path = request.session['msg']['t_yaml_file_path']
    if request.session['download_id'] == 2:  # 只发送html最终测试报告
        file_path = request.session['msg']['Auto_process_path']
        user_name = request.session["user_id"]
        try:
            # 邮件发送
            fail_num = request.session['main_process']['fail_num']
            pk = request.session['main_process']['total_pk']
            request.session['main_process']['total_pk'] = ""
            tmp = models.File.objects.filter(pk=pk, owner=models.User.objects.get(name=user_name))
            if tmp:
                Inside_action.send_emial_appendix(user_name, file_path, tmp[0], fail_num)
            # else:
            #     Inside_action.send_emial_appendix(user_name, file_path)

        except Exception as e:
            print("error in page_download:{}".format(e))
    if (file_name == None):  # 直接访问禁止
        return HttpResponse("禁止直接访问！")
    t = loader.get_template('process/download_h.html')
    context = {'file_name': file_name, "username": request.session["user_id"], }
    return HttpResponse(t.render(context, request))


"""#总用例上传最终测试过程"""


# todo:!!!!方法比较冗余  之后精简代码
# @Decoration.check_login
@csrf_exempt  # CSRF必用
def Automatic_Process(request):
    """
    总用例上传的页面
    :param request:
    :return:
    """
    global T_folder
    if request.method == 'POST':
        T_form = Tyaml(request.POST)
        file = request.FILES.get('file')  # 获取文件对象，包括文件名文件大小和文件内容
        curttime = time.strftime("%Y%m%d")

        if request.session['count_id_Auto'] == "0" and request.session['count_id_Auto']:
            T_folder = request.session['ran_id_Auto']
            # request.session['folder']=Only_folder
        request.session['count_id_Auto'] = "1"
        request.session['curttime_Auto' \
                        ''] = curttime

        # 规定上传目录
        request.session['upload_folder_Auto'] = os.path.join(settings.MEDIA_ROOT, 'T_Yaml_For_test', curttime,
                                                             request.session['user_id'], T_folder)
        upload_url = request.session['upload_folder_Auto']
        # 判断文件夹是否存在
        folder = os.path.exists(upload_url)
        if not folder:
            os.makedirs(upload_url)
            print("创建文件夹")
        if file:
            file_name = file.name
            # 判断文件是是否重名，懒得写随机函数，重名了，文件名加时间
            if os.path.exists(os.path.join(upload_url, file_name)):
                name, etx = os.path.splitext(file_name)
                addtime = time.strftime("%Y%m%d%H%M%S")
                finally_name = name + "_" + addtime + etx
                # print(name, etx, finally_name)
            else:
                finally_name = file.name
            # 文件分块上传
            upload_file_to = open(os.path.join(upload_url, finally_name), 'wb+')
            # 保存上传的总用例的文件名
            request.session['file_name_Auto'] = finally_name
            for chunk in file.chunks():
                upload_file_to.write(chunk)
            upload_file_to.close()
            # 返回文件的URl
            file_upload_url = settings.MEDIA_URL + 'attachment/' + curttime + '/' + finally_name
            # 构建返回值
            response_data = {}
            response_data['FileName'] = file_name
            response_data['FileUrl'] = file_upload_url
            response_json_data = json.dumps(response_data)  # 转化为Json格式
            # session = Session.objects.get(pk=request.session.session_key)
            # #上传文件pk的值  同步操作
            #
            # print(session.get_decoded())
            return HttpResponse(response_json_data)
    else:
        T_form = Tyaml()
        # 标识位  下次访问重新生成ranstr
        request.session['count_id_Auto'] = "0"
        # 生成随机字符 用于身份判别
        request.session['ran_id_Auto'] = ''.join(random.sample(string.ascii_letters + string.digits, 20))
    t = loader.get_template('generate/OutPut_report.html')
    context = {'T_form': T_form, 'username': request.session['user_id']}
    # count_id_Auto值是否改变？
    # session = Session.objects.get(pk=request.session.session_key)
    # print(session.get_decoded())
    return HttpResponse(t.render(context, request))


def Automatic_Process_middlesite(request):
    """
    总用例上传(点击结束上传按钮后）！
    :param request:
    :return:
    """
    # 获取表单数据
    if request.method == 'POST':  # 如果为post则必须要提交
        T_form = Tyaml(request.POST)
        if request.session['count_id_Auto'] == "0":  # 证明上传过文件
            messages.error(request, "请上传文件后进行提交")
            # 重定向回原页面
            return redirect(reverse('generate_yaml:Automatic_Process'))
            # return HttpResponse(t.render(context, request))
        else:
            if T_form.is_valid():
                app_path = T_form.cleaned_data["search_T"]
                app_database = models.App.objects.get(app_path=app_path)
                if app_database.judge_condition_compile():
                    messages.error(request, "正在编译！无法使用")
                    # 重定向回原页面
                    return redirect(reverse('generate_yaml:Automatic_Process'))
                request.session['tmp_time'] = time.strftime("%Y-%m-%d_%H_%M_%S")
                request.session['base_path'] = os.path.abspath(
                    (os.path.join(os.getcwd(), "..")) + file_folder + report_folder)
                # 传递给main过程的变量
                request.session['main_process'] = {}
                # tmp['name'] = request.session.session_key
                request.session['main_process']['app_path'] = T_form.cleaned_data["search_T"]
                # 因为有打包操作必须分割开   /用时间文件夹分割
                # tmp['report_path'] =os.path.join(base_path,tmp_time)
                request.session['main_process']['report_path'] = request.session['base_path'] + "/" + request.session[
                    'tmp_time']
                request.session['main_process']['Total_case_path'] = os.path.join(request.session['upload_folder_Auto'],
                                                                                  request.session['file_name_Auto'])

                # run的该文件的主键值
                file_pk = Inside_action.up_load_to_file_manage(
                    request.session['user_id'],
                    os.path.join(request.session['upload_folder_Auto'], request.session['file_name_Auto']),
                    'Total').pk
                request.session['main_process']['total_pk'] = file_pk
                # TODO 获取上一级目录名！通过它来搜索
                return render(request, "process/progress_bar.html")


# ajax先发送id给它  让它跑起来  再用第二个函数进行进度查询
def Progreass_bar_html(request):
    """
     进度条页面时，将数据丢往后端处理
     需要main_process的值
    :param request:
    :return:
    """
    if (request.method == "POST"):  # 用于请求文件的pk号以便下一个用户查询进度问题
        pk = request.session['main_process']['total_pk']
        File_database = models.File.objects.get(pk=pk)
        # 初始化进度条的值
        File_database.init_progress_bar_value()
        # 返回该文件的主键值
        response_json_data = json.dumps(pk)
        return HttpResponse(response_json_data)

    else:  # get
        time.sleep(1)
        pk = request.session['main_process']['total_pk']
        request.session['main_process']['fail_num'] = main.Auto_process(request.session['main_process'], pk)
        # 压缩文件名
        file_name = request.session['tmp_time'] + "-" + request.session["user_id"] + "_report" + ".zip"
        # 输出压缩的文件夹
        zip_path = request.session['base_path'] + zip_folder
        if not zip_path:
            os.makedirs(zip_path)
        # 压缩文件名
        need_compress = request.session['main_process']['report_path']
        zip_path_name = os.path.join(zip_path, file_name)
        # 压缩文件
        zip_file.compress_file(need_compress, zip_path_name)
        # 最终输出为
        path_case = os.path.join(zip_path, file_name)
        download_url = reverse("generate_yaml:download_page", kwargs={'file_name': str(file_name)})
        context_fun = {}
        context_fun['Auto_process_path'] = path_case
        request.session['msg'] = context_fun
        # 保存到file_manage
        Inside_action.up_load_to_file_manage(request.session['user_id'], path_case, "report")
        # 发送邮件判定
        # request.session['main_process']['Total_case_path']
        # 下载标识位
        request.session['download_id'] = 2
        try:
            os.system('killall -9 app_x86')
        except Exception as e:
            print(e)
        # return redirect(download_url)
        return HttpResponse(download_url)


# 用全局变量处理进度，更新后台记录值  get_id_flag用于知道是否是Auto代码需要获取id值
def Progress_bar_ajax(request):
    """
    接收ajax传回来的数据并查询发送，负责查看进度
    :param request:
    :return:
    """
    try:
        if (request.method == "POST"):
            # 临时身份字符串
            pk = request.POST.get('pk')
            File_database = models.File.objects.get(pk=pk)
            response_data = {}
            response_data["percentage"] = File_database.get_progress_bar_value()
            # response_data["percentage"] = tmp_per
            response_json_data = json.dumps(response_data)
            return HttpResponse(response_json_data)
    except Exception as e:
        print(e)
        response_data = {}
        response_data["percentage"] = 99
        # response_data["percentage"] = tmp_per
        response_json_data = json.dumps(response_data)
        return HttpResponse(response_json_data)


"""错误视图函数定义
def bad_request(request):
    pass
    # return render(request, '400.html')


def permission_denied(request):
    return render(request, '403.html')


def page_not_found(request):
    return render(request, '404.html')


def error(request):
    return render(request, '500.html')"""


def inside_upload(request, pk):
    pass
